using System;
using System.Collections.Generic;
using System.Text;
using NBusiness.CodeDom.Compiler;
using System.CodeDom;
using System.IO;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using NBusiness.CodeDom;
using System.Web.UI.Design.WebControls;
using NBusiness.Data.Web;
using System.Web.UI.WebControls;
using System.Collections;

namespace NBusiness.Templates
{
    public class ScaffoldingTemplate : ITemplate
    {
        #region ITemplate Members

        #region Generate
        public EntityResourceFile[] Generate(NBusiness.CodeDom.Entity[] entities)
        {
            List<EntityResourceFile> files = new List<EntityResourceFile>();
            foreach (Entity entity in entities)
            {
                CodeCompileUnit unit = new CodeCompileUnit();
                CodeNamespace n = new CodeNamespace((entity.Parent as EntityFamily).Fullname);
                string fileName = "Scaffolding\\" + entity.Fullname + ".cs";

                n.Comments.Add(new CodeCommentStatement(fileName + " - '" + this.GetType().FullName + "'"));
                n.Comments.Add(new CodeCommentStatement("This file was automatically generated by NBusiness"));
                n.Comments.Add(new CodeCommentStatement("on " + DateTime.Now.ToLongTimeString()));

                n.Imports.Add(new CodeNamespaceImport("System"));
                n.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));
                n.Imports.Add(new CodeNamespaceImport("System.Data.Common"));
                n.Imports.Add(new CodeNamespaceImport("System.Data"));
                n.Imports.Add(new CodeNamespaceImport("System.ComponentModel"));
                n.Imports.Add(new CodeNamespaceImport("NBusiness.Data"));
                n.Imports.Add(new CodeNamespaceImport("NBusiness.Utilities"));
                n.Imports.Add(new CodeNamespaceImport("NBusiness.Data.Validation"));
                unit.Namespaces.Add(n);

                StringWriter sw = new StringWriter();
                CodeTypeDeclaration d = CreateMainClass(entity);
                if (d != null)
                {
                    n.Types.Add(d);

                    CreateConstructors(entity, d);
                    //CreateFieldNames(entity, d);
                    //CreateFieldsAndProperties(entity, d);
                    //CreateCriteria(entity, d);
                    //CreateFactoryMethods(entity, d);
                    //CreateRules(entity, d);
                    //CreateDataAccessMethods(entity, d);
                    //CreateRelationships(entity, d);
                    //CreateGetInfoObject(entity, d);
                    //CreateActions(entity, d);
                    //CreateGetChildTypes(entity, d);

                    CSharpCodeProvider cscp = new CSharpCodeProvider();
                    CodeGeneratorOptions op = new CodeGeneratorOptions();
                    op.BlankLinesBetweenMembers = false;
                    op.BracingStyle = "C";
                    op.ElseOnClosing = false;
                    op.IndentString = "\t";
                    op.VerbatimOrder = true;
                    cscp.GenerateCodeFromCompileUnit(unit, sw, op);
                }

                string code = sw.GetStringBuilder().ToString();
                byte[] data = Encoding.UTF8.GetBytes(code);

                EntityResourceFile file = new EntityResourceFile(
                    fileName,
                    EntityBuildAction.Compile);
                file.Data = data;

                files.Add(file);
            }
            return files.ToArray();
        }

        private void CreateConstructors(Entity entity, CodeTypeDeclaration d)
        {
            //none yet...
        }

        private CodeTypeDeclaration CreateMainClass(Entity entity)
        {
            CodeTypeDeclaration d = new CodeTypeDeclaration();
            d.BaseTypes.Add(new CodeTypeReference(typeof(CompositeDataBoundControl)));
            d.IsClass = true;
            d.Name = entity.Name + "Scaffold";

            CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(
                new CodeTypeReference(typeof(DataBoundControlDesigner)));
            CodeAttributeArgument arg1 = new CodeAttributeArgument();
            attribute.Arguments.Add(new CodeAttributeArgument(new CodeTypeReferenceExpression(typeof(ScaffoldDesigner))));
            attribute.Arguments.Add(new CodeAttributeArgument(new CodeTypeReferenceExpression(typeof(DataBoundControlDesigner))));

            d.CustomAttributes.Add(attribute);

            return d;
        }

        private void CreateChildControlsOverride(Entity entity, CodeTypeDeclaration declaration)
        {
            //Create method declaration
            CodeMemberMethod createChildControls = new CodeMemberMethod();
            createChildControls.ReturnType = new CodeTypeReference(typeof(int));
            createChildControls.Name = "CreateChildControls";
            createChildControls.Attributes = MemberAttributes.Override | MemberAttributes.Public;
            createChildControls.Parameters.Add(new CodeParameterDeclarationExpression(typeof(IEnumerable), "dataSource"));
            createChildControls.Parameters.Add(new CodeParameterDeclarationExpression(typeof(bool), "databinding"));
            createChildControls.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Create Child Controls"));
            createChildControls.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, ""));
            declaration.Members.Add(createChildControls);

            //Declare the table
            CodeVariableDeclarationStatement table = new CodeVariableDeclarationStatement(
                typeof(Table), 
                "table",
                new CodeObjectCreateExpression(typeof(Table)));

            //Declare a foreach
            CodeVariableDeclarationStatement count = new CodeVariableDeclarationStatement(typeof(int), "count");
            

            //Declare a row
            CodeVariableDeclarationStatement row = new CodeVariableDeclarationStatement(
                typeof(TableRow), 
                "row",
                new CodeObjectCreateExpression(typeof(TableRow)));

                CodeVariableReferenceExpression rowRef = new CodeVariableReferenceExpression("row");
                CodePropertyReferenceExpression rowControlsRef = new CodePropertyReferenceExpression(
                    rowRef,
                    "Controls");

            foreach (EntityField field in entity.Fields)
            {
                



                CodeVariableReferenceExpression tableRef = new CodeVariableReferenceExpression("table");
                //CodeMethodInvokeExpression add = new CodeMethodInvokeExpression(controls, "Add", row);
            }
        }
        #endregion

        public event EventHandler<EntityParserErrorEventArgs> Warning;
        protected void OnWarning(EntityParserError error)
        {
            if (Warning != null) Warning(this, new EntityParserErrorEventArgs(error));
        }
        #endregion
    }
}
